import 'cnd_operator.dart';

/// 条件对象
///
/// 用于定义查询条件信息，配合cndList和toMap()使用
class Cnd {
  /// 列名
  final String name;

  /// 操作符，默认为等于
  final CndOperator op;

  /// 是否忽略空值，默认为true
  final bool ignoreNull;

  /// 表别名，用于多表查询
  final String? tableAlias;

  /// 通用构造器
  const Cnd({
    required this.name,
    this.op = CndOperator.eq,
    this.ignoreNull = true,
    this.tableAlias,
  });

  /// 等于条件
  const Cnd.eq({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.eq;

  /// 不等于条件
  const Cnd.ne({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.ne;

  /// 大于条件
  const Cnd.gt({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.gt;

  /// 大于等于条件
  const Cnd.ge({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.ge;

  /// 小于条件
  const Cnd.lt({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.lt;

  /// 小于等于条件
  const Cnd.le({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.le;

  /// LIKE条件
  const Cnd.like({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.like;

  /// NOT LIKE条件
  const Cnd.notLike({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.notLike;

  /// IS NULL条件
  const Cnd.isNull({
    required this.name,
    this.tableAlias,
  })  : op = CndOperator.isNull,
        ignoreNull = false;

  /// IS NOT NULL条件
  const Cnd.isNotNull({
    required this.name,
    this.tableAlias,
  })  : op = CndOperator.isNotNull,
        ignoreNull = false;

  /// IN条件
  const Cnd.in_({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.in_;

  /// NOT IN条件
  const Cnd.notIn({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.notIn;

  /// BETWEEN条件
  const Cnd.between({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.between;

  /// NOT BETWEEN条件
  const Cnd.notBetween({
    required this.name,
    this.ignoreNull = true,
    this.tableAlias,
  }) : op = CndOperator.notBetween;

  /// 获取完整的列名（包含表别名）
  String getFullColumnName() {
    return tableAlias != null ? '$tableAlias.$name' : name;
  }

  /// 是否应该忽略该值
  bool shouldIgnore(dynamic value) {
    if (!ignoreNull) return false;

    if (value == null) return true;

    if (value is String && value.isEmpty) return true;

    if (value is Iterable && value.isEmpty) return true;

    return false;
  }
}

/// 范围条件辅助类
class Range<T> {
  final T? start;
  final T? end;
  final bool includeStart;
  final bool includeEnd;

  const Range({
    this.start,
    this.end,
    this.includeStart = true,
    this.includeEnd = true,
  });

  bool get isValid => start != null || end != null;
  bool get isBetween => start != null && end != null;
  bool get isStartOnly => start != null && end == null;
  bool get isEndOnly => start == null && end != null;
}

/// 日期范围条件
typedef DateRange = Range<DateTime>;

/// 数字范围条件
typedef NumberRange = Range<num>;
